#pragma once

#include <iostream>
#include <string>
#include <memory>
#include <jsoncpp/json/json.h>
#include <functional>
#include "Socket.hpp"
#include "Log.hpp"


using namespace LogModule;
using namespace SocketModule;


class Request
{
public:
    Request()
    {}

    Request(int x, int y, int op)
        :_x(x)
        ,_y(y)
        ,_op(op)
    {}

    std::string Serialize()
    {
        //利用Json进行序列化和反序列化
        Json::Value root;
        root["x"] = _x;
        root["y"] = _y;
        root["operator"] = _op;

        Json::FastWriter writer;
        std::string s = writer.write(root);
        return s;
    }

    bool Deserialize(std::string& in)
    {
        Json::Value root;
        Json::Reader reader;
        if(reader.parse(in, root))
        {
            _x = root["x"].asInt();
            _y = root["y"].asInt();
            _op = root["operator"].asInt();
            return true;
        }
        return false;
    }

    int X() {return _x;}
    int Y() {return _y;}
    char Oper() {return _op;}

private:
    int _x;
    int _y;
    char _op;
};

class Response
{
public:
    Response()  
    {}

    Response(int result, int exitcode)
        :_result(result)
        ,_exit_code(exitcode)
    {}
    
    void SetResult(int result)
    {
        _result = result;
    }

    void SetExitCode(int code)
    {
        _exit_code = code;
    }

    std::string Serialize()
    {
        Json::Value root;
        root["result"] = _result;
        root["exitcode"] = _exit_code;

        Json::FastWriter writer;
        std::string s = writer.write(root);
        return s;
    }

    bool Deserialize(std::string& in)
    {
        Json::Value root;
        Json::Reader reader;
        if(reader.parse(in, root))
        {
            _result = root["result"].asInt();
            _exit_code = root["exitcode"].asInt();
            return true;
        }
        return false;
    }

    //client

    void ShowResult()
    {
        std::cout << "the calculation result: " << _result << "[" << _exit_code << "]" << std::endl;
    }


private:
    int _result;
    int _exit_code;
};

const std::string sep = "\r\n";

using func_t = std::function<Response(Request& req)>;

class Protocol
{
public:
    Protocol(){}
    Protocol(func_t func)
        :_func(func)
    {}

    std::string Encode(const std::string& jsonstr)
    {
        std::string len = std::to_string(jsonstr.size());
        return len + sep + jsonstr + sep;
    }

    //该函数会循环调用，获取到一个完整的jsonstr
    //报文形式：jsonstr的长度 + 分隔符 + jsonstr + 分隔符
    bool Decode(std::string& buffer, std::string* package)
    {
        ssize_t pos = buffer.find(sep);
        if(pos == std::string::npos)
            return false;
        std::string package_len_str = buffer.substr(0, pos);
        
        //获取到Json字符串的长度
        int package_len = std::stoi(package_len_str);
        //计算整个报文的长度
        int target_len = package_len_str.size() + 2 * sep.size() + package_len;
        if(buffer.size() < target_len)
            return false;
        
        //这里至少可以获取一个完整的报文 jsonstr的长度 + 分隔符 + jsonstr + 分隔符
        *package = buffer.substr(pos + sep.size(), package_len);
        buffer.erase(0, target_len);
        return true;
    }

    //根据json字符串构建需求，进行反序列化，回调执行NetCal模块获取请求
    std::string BuildResponse(std::string& package)
    {
        Request req;
        req.Deserialize(package);

        Response res = _func(req);
        //对应该做序列化
        std::string json_str = res.Serialize();

        //将其封装成报文
        std::string send_str = Encode(json_str);

        return send_str;
    }

    //client相关的函数

    bool GetResponse(std::shared_ptr<Socket> &client, std::string &resp_buff, Response *resp)
    {
        while (1)
        {
            int n = client->Recv(&resp_buff);
            if (n > 0)
            {
                std::string json_package;
                while (Decode(resp_buff, &json_package));
                {
                    resp->Deserialize(json_package);
                }
                return true;
            }
            else if (n == 0)
            {
                std::cout << "server quit " << std::endl;
                return false;
            }
            else
            {
                std::cout << "recv error" << std::endl;
                return false;
            }
        }
    }

    std::string BuildRequestString(int x, int y, char oper)
    {
        Request req(x, y, oper);
        std::string json_req = req.Serialize();

        return Encode(json_req);
    }

private:
    //回调函数，执行NetCal模块
    func_t _func;
};

